﻿using System;
using Calimbra.Runtime.Contracts;
using Calimbra.Runtime.Contracts;
using Calimbra.Runtime.Data;

namespace Calimbra.Runtime.Functions
{
    public class Trigger<T> : ITrigger<T>
    {
        public event Action<T> Output;

        private T message;
        private bool hasFireSolution;

        public void Input(T message)
        {
            this.message = message;
            FireAtWill();
        }

        public void Fire()
        {
            hasFireSolution = true;
            FireAtWill();
        }

        private void FireAtWill()
        {
            if (hasFireSolution && message != null)
            {
                Output(message);
                hasFireSolution = false;
            }
        }

        public void InputAdapter(IMessage input, Action<IMessage> outputContinuation)
        {
            T resultInput = default(T);
            Output += r => resultInput = r;
            Input((T)input.Data);
            
            if (!ReferenceEquals(resultInput, null))
                outputContinuation(new Message("Trigger.out", resultInput + "Input"));
        }

        public void FireAdapter(IMessage input, Action<IMessage> outputContinuation)
        {
            T resultFire = default(T);
            Output += r => resultFire = r;
            Fire();
            
            if (!ReferenceEquals(resultFire, null))
                outputContinuation(new Message("Trigger.out", resultFire + "Fire"));
        }

        public OperationAdapter GetAdapter(string operationName)
        {
            switch (operationName)
            {
                case "Input":
                    return InputAdapter;
                case "Fire":
                    return FireAdapter;
                default:
                    throw new InvalidOperationException(string.Format("Operation name {0} does not exist."));
            }
        }
    }
}